/*This file is part of jasmo.

jasmo is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

jasmo is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with jasmo.  If not, see <http://www.gnu.org/licenses/>.*/

package com.lab9.jasmo.service;

import java.util.Date;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.Future;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.log4j.Logger;

import com.lab9.jasmo.domain.IMonitoredService;
import com.lab9.jasmo.domain.ServiceState;

/**
 * this is the monitoring service that schedules the probing of monitored
 * services.
 * 
 * @author dpsenner@gmail.com
 * 
 */
public final class MonitoringService {
	private static final Logger logger = Logger.getLogger(MonitoringService.class);
	
	private BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<Runnable>();
	private ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(5, 25, 1000, TimeUnit.SECONDS, workQueue);

	private List<IMonitoredService> allMonitoredServices = new LinkedList<IMonitoredService>();
	private boolean running;

	/**
	 * this method starts the scheduler.
	 */
	public void startScheduler() {
		running = true;
		setup();
		run();
	}
	
	/**
	 * this method stops the scheduler.
	 */
	public void stopScheduler() {
		running = false;
	}
	
	private void setup() {
		logger.info("ENTERING - setup()");
		
		// read config
		try
		{
			allMonitoredServices = new MonitoringServiceConfigurator().ReadConfig();
		}
		catch (ConfigurationFailedException e)
		{
			logger.error(e);
			allMonitoredServices = new LinkedList<IMonitoredService>();
		}
		
		logger.info("EXITING - setup()");
	}

	private void run() {
		logger.info("ENTERING - run()");
		while (running) {
			// retrieve all monitoring services and add them to the scheduler
			for (IMonitoredService service : allMonitoredServices) {
				// check if the service is not currently working
				if (service.State() != ServiceState.PROBING) {
					// check if it is really time to do another probe
					if (service.LastProbe().before(new Date(new Date().getTime() + service.ProbeTimeout()))) {
						// check if all depending services are up
						boolean dependingsOk = true;
						for(IMonitoredService dependency : service.DependingServices()) {
							switch(dependency.State()) {
								case OK:
									break;
								default:
									dependingsOk = false;
								break;
							}
						}
						// if all are up, start the probing
						if ( dependingsOk) {
							Future<?> future = threadPoolExecutor.submit(new MonitoredServiceRunnable(service));
							if ( future != null) {
								logger.info("started probe of service " + service);
							}
						}
					}
				}
			}

			try {
				Thread.sleep(1000);
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
		logger.info("EXITING - run()");
	}
}
